using System;
using System.Collections;
using System.IO;
using System.Xml;
using System.Net;

public class UserList
{

	private Hashtable list = new Hashtable();

	//====================================================================
	// Operations for all users: connect, disconnect, broadcast a message
	//====================================================================

	#region " Connect, Disconnect, SendText "

	public void Connect()
	{
		foreach (RemoteUser u in list.Values) {
			u.ConnectInitiate(LocalUserName, LocalUserAddress);
		}
	}

	public void Disconnect()
	{
		foreach (RemoteUser u in list.Values) {
			u.Disconnect();
		}
	}

	//====================================================================

	public void SendText(string Text)
	{
		foreach (RemoteUser u in list.Values) {
			u.SendText(Text);
		}
	}

	public void SendStatus(UserStatus NewStatus)
	{
		if (NewStatus == UserStatus.Offline) return; 
		// Cannot be offline when sending.

		foreach (RemoteUser u in list.Values) {
			u.SendStatus(NewStatus);
		}
	}

	#endregion

	//====================================================================

	#region " Events "

	//====================================================================
	// Events
	//====================================================================

	public event UserConnectedEventHandler UserConnected;
	public delegate void UserConnectedEventHandler(RemoteUser Sender);
	public event UserDisconnectedEventHandler UserDisconnected;
	public delegate void UserDisconnectedEventHandler(RemoteUser Sender);
	public event UserReceivedTextEventHandler UserReceivedText;
	public delegate void UserReceivedTextEventHandler(RemoteUser Sender, string Text);
	public event UserStatusChangedEventHandler UserStatusChanged;
	public delegate void UserStatusChangedEventHandler(RemoteUser Sender);

	private void OnUserConnected(RemoteUser Sender)
	{
		if (UserConnected != null) {
			UserConnected(Sender);
		}
	}

	private void OnUserDisconnected(RemoteUser Sender)
	{
		if (UserDisconnected != null) {
			UserDisconnected(Sender);
		}
	}

	private void OnUserReceivedText(RemoteUser Sender, string Text)
	{
		if (UserReceivedText != null) {
			UserReceivedText(Sender, Text);
		}
	}

	private void OnUserStatusChanged(RemoteUser Sender)
	{
		if (UserStatusChanged != null) {
			UserStatusChanged(Sender);
		}
	}

	#endregion

	//====================================================================
	// High-level List management (Load, Save, Modify)
	//====================================================================

	#region " This list's Properties: LocalUserName, LocalUserAddress, FileName "

	private string mLocalUserAddress;
	protected string LocalUserAddress {
		get { return mLocalUserAddress; }
		set { mLocalUserAddress = value; }
	}

	private string mLocalUserName;
	public string LocalUserName {
		get { return mLocalUserName; }
		set { mLocalUserName = value; }
	}

	private string mFileName = "ChatSettings.xml";
	public string FileName {
		get { return mFileName; }
		set { mFileName = value; }
	}

	#endregion

	#region " Load from XML "

	public void Load()
	{
		try {
			XmlDocument Doc = new XmlDocument();
			Doc.Load(FileName);

			XmlNode Node1 = Doc.SelectSingleNode("/Chat/LocalUser");
			LocalUserName = Node1["Name"].InnerText;
			LocalUserAddress = Node1["Address"].InnerText;

			XmlNodeList Nodes = Doc.SelectNodes("/Chat/Users/User");

			foreach (XmlNode node in Nodes) {
				string NewName = node["Name"].InnerText;
				string NewAddress = node["Address"].InnerText;
				RemoteUser NewUser = AddRemoteUser(NewName, NewAddress);
			}
		}

		catch (System.IO.FileNotFoundException e) {
		}
		finally {
			if (LocalUserName == "") LocalUserName = Environment.UserName; 
			if (LocalUserAddress == "") LocalUserAddress = Environment.MachineName; 
		}
	}

	#endregion

	#region " Save to XML "

	public void Save()
	{
		using(StreamWriter textWriter = new StreamWriter(FileName, false))
		using(XmlTextWriter xmlWriter = new XmlTextWriter(textWriter))
		{
			xmlWriter.Formatting = Formatting.Indented;

			//====================================================================
			xmlWriter.WriteStartDocument();
			xmlWriter.WriteStartElement("Chat");

			xmlWriter.WriteStartElement("LocalUser");
			xmlWriter.WriteElementString("Name", LocalUserName);
			xmlWriter.WriteElementString("Address", LocalUserAddress);
			xmlWriter.WriteEndElement();

			xmlWriter.WriteStartElement("Users");
			foreach (RemoteUser User in list.Values) {
				xmlWriter.WriteStartElement("User");
				xmlWriter.WriteElementString("Name", User.Name);
				xmlWriter.WriteElementString("Address", User.Address);
				xmlWriter.WriteEndElement();
			}
			xmlWriter.WriteEndElement();

			xmlWriter.WriteEndElement();
			xmlWriter.WriteEndDocument();
		}
	}

	#endregion

	//====================================================================
	// Add user
	//====================================================================

	#region " Add users to the list "

	// called to add a user who contacted us with an invitation.
	public void AddUserIncomingRequest(string Name, string Address, UserConnection ExistingConnection)
	{
		RemoteUser NewUser = AddRemoteUser(Name, Address);
		NewUser.ConnectRespond(ExistingConnection);
		Save();
	}

	// called to add a user whom we contacted.
	public void AddUserOutgoingRequest(string Name, string Address)
	{
		RemoteUser NewUser = AddRemoteUser(Name, Address);
		NewUser.ConnectInitiate(LocalUserName, LocalUserAddress);
		Save();
	}

	//====================================================================

	private RemoteUser AddRemoteUser(string Name, string Address)
	{
		RemoteUser functionReturnValue = null;
		RemoteUser NewUser = new RemoteUser(Name, Address);

		// map user's events to this list's events
		NewUser.Connected += this.OnUserConnected;
		NewUser.Disconnected += this.OnUserDisconnected;
		NewUser.ReceivedText += this.OnUserReceivedText;
		NewUser.StatusChanged += this.OnUserStatusChanged;

		Add(NewUser);
		return NewUser;
		return functionReturnValue;
	}

	//====================================================================

	protected void Add(RemoteUser NewUser)
	{
		list.Add(NewUser.Name, NewUser);
	}

	#endregion

	//====================================================================
	// Current user statistics.
	// Count
	// OnlineUsersCount
	// AnyUsersOnline
	// AllUsersNotAvailable
	//====================================================================

	#region " Current user statistics "

	public int Count {
		get { return list.Count; }
	}

	public int OnlineUsersCount()
	{
		int i = 0;

		foreach (RemoteUser u in list.Values) {
			if (u.IsOnline()) i += 1;
		}

		return i;
	}

	public bool AnyUsersOnline()
	{
		bool functionReturnValue = false;
		return OnlineUsersCount() > 0;
		return functionReturnValue;
	}

	public bool AllUsersNotAvailable()
	{
		foreach (RemoteUser u in list.Values) {
			if (u.Status == UserStatus.Online) return false; 
		}
		return true;
	}

	#endregion

	//====================================================================
	// List operations:
	// Item(String Name)
	// GetEnumerator
	//====================================================================

	#region " List operations "

	// Return user object by name
	public RemoteUser this[string itemName]
	{
		get { return (RemoteUser)list[itemName]; }
	}

	public System.Collections.IEnumerator GetEnumerator()
	{
		System.Collections.IEnumerator functionReturnValue = null;
		return list.Values.GetEnumerator();
		return functionReturnValue;
	}

	#endregion

}
